﻿using System;
using System.Linq;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using TestHarnessWebRole.Data;
using AntsCode.StorageClientExtensions;

namespace TestHarnessWebRole
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // Create tables            
            CloudStorageAccount account = CloudStorageAccount.FromConfigurationSetting("StorageConnectionString");
            CloudTableClient.CreateTablesFromModel(typeof(TestTableServiceContext), account.TableEndpoint.ToString(), account.Credentials);

            // Populate test data
            TestData.AddTestData();

            // Create instance of XTableServiceContext
            TestTableServiceContext context = new TestTableServiceContext(account.TableEndpoint.ToString(), account.Credentials);

            // Raw Customers
            RawCustomerTest.RunQuery(context, from c in context.Customer
                                              select c);

            // Query Tests
            //// Test 1: Select
            //Test1.RunQuery(context, from c in context.Customer
            //                        select new
            //                        {
            //                            c.FirstName,
            //                            c.LastName
            //                        });

            //// Test 2: Join
            //Test2.RunQuery(context, from o in context.Order
            //                        join c in context.Customer on o.CustomerId equals c.RowKey
            //                        select new
            //                        {
            //                            o.OrderNo,
            //                            c.FirstName,
            //                            c.LastName,
            //                            o.Total
            //                        });

            //// Test 3: Join (asynchronous)
            //Test3.RunQuery(context, from o in context.Order
            //                        join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers", Async = true } equals new { c.RowKey, c.PartitionKey, Async = true }
            //                        select new
            //                        {
            //                            o.OrderNo,
            //                            c.FirstName,
            //                            c.LastName,
            //                            o.Total
            //                        });

            //// Test 4: Join and Where
            //Test4.RunQuery(context, from o in context.Order
            //                        join c in context.Customer on o.CustomerId equals c.RowKey
            //                        where o.OrderNo == "20020"
            //                        select new
            //                        {
            //                            o.OrderNo,
            //                            c.FirstName,
            //                            c.LastName,
            //                            o.Total
            //                        });

            //// Test 5: Join on multiple properties
            //Test5.RunQuery(context, from o in context.Order
            //                        join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers" } equals new { c.RowKey, c.PartitionKey }
            //                        select new
            //                        {
            //                            o.OrderNo,
            //                            c.FirstName,
            //                            c.LastName,
            //                            o.Total
            //                        });

            //// Test 6: Join on multiple properties (asynchronous)
            //Test6.RunQuery(context, from o in context.Order
            //                        join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers", Async = true } equals new { c.RowKey, c.PartitionKey, Async = true }
            //                        where o.OrderNo == "20020"
            //                        select new
            //                        {
            //                            o.OrderNo,
            //                            c.FirstName,
            //                            c.LastName,
            //                            o.Total
            //                        });

            //// Test 7: Multiple Joins (companies are dependent on customers)
            //Test7.RunQuery(context, from o in context.Order
            //                        join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers" } equals new { c.RowKey, c.PartitionKey }
            //                        join co in context.Company on new { RowKey = c.CompanyId, PartitionKey = "Companies" } equals new { co.RowKey, co.PartitionKey }
            //                        join l in context.Location on new { RowKey = co.LocationId, PartitionKey = "Locations" } equals new { l.RowKey, l.PartitionKey }
            //                        select new
            //                        {
            //                            o.OrderNo,
            //                            co.Name,
            //                            c.FirstName,
            //                            c.LastName,
            //                            o.Total,
            //                            Location = l.Name
            //                        });

            //// Test 8: Multiple Joins (companies are dependent on orders)
            //Test8.RunQuery(context, from o in context.Order
            //                        join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers" } equals new { c.RowKey, c.PartitionKey }
            //                        join co in context.Company on new { RowKey = o.CompanyId, PartitionKey = "Companies" } equals new { co.RowKey, co.PartitionKey }
            //                        join l in context.Location on new { RowKey = co.LocationId, PartitionKey = "Locations" } equals new { l.RowKey, l.PartitionKey }
            //                        select new
            //                        {
            //                            o.OrderNo,
            //                            co.Name,
            //                            c.FirstName,
            //                            c.LastName,
            //                            o.Total,
            //                            Location = l.Name
            //                        });

            //// Test 9: Multiple Joins (companies & locations are dependent on orders)
            //Test9.RunQuery(context, from o in context.Order
            //                        join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers" } equals new { c.RowKey, c.PartitionKey }
            //                        join co in context.Company on new { RowKey = o.CompanyId, PartitionKey = "Companies" } equals new { co.RowKey, co.PartitionKey }
            //                        join l in context.Location on new { RowKey = o.LocationId, PartitionKey = "Locations" } equals new { l.RowKey, l.PartitionKey }
            //                        select new
            //                        {
            //                            o.OrderNo,
            //                            co.Name,
            //                            c.FirstName,
            //                            c.LastName,
            //                            o.Total,
            //                            Location = l.Name
            //                        });

            //// Test 10: Multiple Joins (asynchronous)
            //Test10.RunQuery(context, from o in context.Order
            //                         join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers", Async = true } equals new { c.RowKey, c.PartitionKey, Async = true }
            //                         join co in context.Company on new { RowKey = o.CompanyId, PartitionKey = "Companies", Async = true } equals new { co.RowKey, co.PartitionKey, Async = true }
            //                         join l in context.Location on new { RowKey = o.LocationId, PartitionKey = "Locations", Async = true } equals new { l.RowKey, l.PartitionKey, Async = true }
            //                         select new
            //                         {
            //                             o.OrderNo,
            //                             co.Name,
            //                             c.FirstName,
            //                             c.LastName,
            //                             o.Total,
            //                             Location = l.Name
            //                         });

            //// Test 11: First
            //Test11.InitSingle(context);
            //Test11.RunSingle(context, (from c in context.Customer
            //                           where c.FirstName == "Peter"
            //                           select new
            //                           {
            //                               c.FirstName,
            //                               c.LastName
            //                           }).First());

            //// Test 12: FirstOrDefault
            //Test12.InitSingle(context);
            //Test12.RunSingle(context, (from c in context.Customer
            //                           where c.FirstName == "DoesNotExist"
            //                           select new
            //                           {
            //                               c.FirstName,
            //                               c.LastName
            //                           }).FirstOrDefault());

            //// Test 13: Take
            //Test13.RunQuery(context, (from c in context.Customer
            //                          select new
            //                          {
            //                              c.FirstName,
            //                              c.LastName
            //                          }).Take(3));

            //// Test 14: Join & FirstOrDefault
            //Test14.InitSingle(context);
            //Test14.RunSingle(context, (from o in context.Order
            //                           join c in context.Customer on o.CustomerId equals c.RowKey
            //                           select new
            //                           {
            //                               o.OrderNo,
            //                               c.FirstName,
            //                               c.LastName,
            //                               o.Total
            //                           }).FirstOrDefault());

            //// Test 15: Get Continuation Token
            //Test15.ShowContinuationToken = true;
            //Test15.RunQuery(context, (from c in context.Customer
            //                          select new
            //                          {
            //                              c.FirstName,
            //                              c.LastName
            //                          }).Take(3));

            //Test16.ContinuationToken = Test15.ContinuationToken;

            //// Test 16: Use Continuation Token
            //Test16.RunQuery(context, (from c in context.Customer
            //                          select new
            //                          {
            //                              c.FirstName,
            //                              c.LastName
            //                          }).Take(3));

            //// Test 17: Get Continuation Token with Join
            //Test17.ShowContinuationToken = true;
            //Test17.RunQuery(context, (from o in context.Order
            //                          join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers" } equals new { c.RowKey, c.PartitionKey }
            //                          join co in context.Company on new { RowKey = o.CompanyId, PartitionKey = "Companies" } equals new { co.RowKey, co.PartitionKey }
            //                          join l in context.Location on new { RowKey = co.LocationId, PartitionKey = "Locations" } equals new { l.RowKey, l.PartitionKey }
            //                          select new
            //                          {
            //                              o.OrderNo,
            //                              co.Name,
            //                              c.FirstName,
            //                              c.LastName,
            //                              o.Total,
            //                              Location = l.Name
            //                          }).Take(3));

            //Test18.ContinuationToken = Test17.ContinuationToken;

            //// Test 18: Use Continuation Token with Join
            //Test18.RunQuery(context, (from o in context.Order
            //                          join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers" } equals new { c.RowKey, c.PartitionKey }
            //                          join co in context.Company on new { RowKey = o.CompanyId, PartitionKey = "Companies" } equals new { co.RowKey, co.PartitionKey }
            //                          join l in context.Location on new { RowKey = co.LocationId, PartitionKey = "Locations" } equals new { l.RowKey, l.PartitionKey }
            //                          select new
            //                          {
            //                              o.OrderNo,
            //                              co.Name,
            //                              c.FirstName,
            //                              c.LastName,
            //                              o.Total,
            //                              Location = l.Name
            //                          }).Take(3));

            //// Test 19: Outer Join
            //Test19.RunQuery(context, from o in context.Order
            //                         join c in context.Customer on o.CustomerId equals c.RowKey into g
            //                         from c in g.DefaultIfEmpty()
            //                         select new
            //                         {
            //                             o.OrderNo,
            //                             c.FirstName,
            //                             c.LastName,
            //                             o.Total
            //                         });


            //// Test 20: Multiple Outer Joins
            //Test20.RunQuery(context, from o in context.Order
            //                         join c in context.Customer on new { RowKey = o.CustomerId, PartitionKey = "Customers" } equals new { c.RowKey, c.PartitionKey }
            //                         join co in context.Company on new { RowKey = c.CompanyId, PartitionKey = "Companies" } equals new { co.RowKey, co.PartitionKey } into oco
            //                         from co in oco.DefaultIfEmpty()
            //                         join l in context.Location on new { RowKey = co == null ? null : co.LocationId, PartitionKey = "Locations" } equals new { l.RowKey, l.PartitionKey } into col
            //                         from l in col.DefaultIfEmpty()
            //                         select new
            //                         {
            //                             o.OrderNo,
            //                             Name = co == null ? null : co.Name,
            //                             Location = l == null ? null : l.Name,
            //                             c.FirstName,
            //                             c.LastName,
            //                             o.Total,
            //                         });

            //// Test 21: OrderBy
            //Test21.RunQuery(context, from x in context.Customer
            //                         orderby x.FirstName
            //                         select new
            //                         {
            //                             x.FirstName,
            //                             x.LastName
            //                         });

            //// Test 22: OrderBy Descending
            //Test22.RunQuery(context, from x in context.Customer
            //                         orderby x.FirstName descending
            //                         select new
            //                         {
            //                             x.FirstName,
            //                             x.LastName
            //                         });

            //// Test 23: ThenBy
            //Test23.RunQuery(context, from x in context.Customer
            //                         orderby x.FirstName, x.LastName
            //                         select new
            //                         {
            //                             x.FirstName,
            //                             x.LastName
            //                         });

            //// Test 24: ThenBy Descending
            //Test24.RunQuery(context, from x in context.Customer
            //                         orderby x.FirstName descending, x.LastName descending
            //                         select new
            //                         {
            //                             x.FirstName,
            //                             x.LastName
            //                         });

            //// Test 25: Query parameter escaping (member, constant, method call, CompareTo, CompareTo with member)
            //string searchValue = "Widget & Co.";

            //Test25.RunQuery(context, from x in context.Company
            //                         where x.Name == searchValue && x.Name == "Widget & Co." && x.Name == GetFilterCriteria() && x.Name.CompareTo("Widget & Co.") >= 0 && x.Name.CompareTo(searchValue) >= 0
            //                         select new
            //                         {
            //                             x.Name
            //                         });

            //// Test 26: Single resource
            //Test26.InitSingle(context);
            //Test26.RunSingle(context, (from x in context.Company
            //                           where x.PartitionKey == "Companies" && x.RowKey == "xxx"
            //                           select new
            //                           {
            //                               x.Name
            //                           }).FirstOrDefault());

            // Denormalization Tests
            // Test 1: Update a company
            var company = (from c in context.Company
                           where c.Name == "Gizmo Inc."
                           select c).First();

            company.Name = "Sprocket Co";

            context.UpdateObject(company);
            context.SaveChanges();




            //var company2 = (from c in context.Company
            //               where c.Name.CompareTo("Widget") >= 0
            //               select c).First();

            //company2.Name = "Sprocket Co";

            //context.UpdateObject(company2);
            //context.SaveChanges(); // This should cause a denormalization error



            DenormTest1.RunQuery(context, from c in context.Customer
                                          select new
                                          {
                                              c.FirstName,
                                              c.LastName,
                                              c.CompanyName
                                          });

            // Test 2: Add a Customer
            Customer customer = new Customer
            {
                FirstName = "Simon",
                LastName = "Smith",
                CompanyId = company.RowKey
            };

            context.AddObject("Customer", customer);
            context.SaveChanges();

            DenormTest2.RunQuery(context, from c in context.Customer
                                          where c.FirstName == "Simon"
                                          select new
                                          {
                                              c.FirstName,
                                              c.LastName,
                                              c.CompanyName
                                          });

            // Test 3: Delete Company
            context.DeleteObject(company);
            context.SaveChanges();

            DenormTest3.RunQuery(context, from c in context.Customer
                                          select new
                                          {
                                              c.FirstName,
                                              c.LastName,
                                              c.CompanyName
                                          });
        }

        public string GetFilterCriteria()
        {
            return "Widget & Co.";
        }
    }
}